package org.campuscontent.ui;

import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import org.jgraph.graph.CellViewRenderer;
import org.jgraph.graph.EdgeView;
import org.jgraph.graph.GraphConstants;
import org.jgraph.graph.VertexRenderer;
import org.jgraph.graph.VertexView;

public class EndNodeView extends VertexView
{
    public static transient EndNodeRenderer renderer = new EndNodeRenderer();

    public EndNodeView()
    {
    }

    /**
     * Returns the intersection of the bounding rectangle and the straight line
     * between the source and the specified point p. The specified point is
     * expected not to intersect the bounds.
     */
    public Point2D getPerimeterPoint( EdgeView edge, Point2D source, Point2D p )
    {
        Rectangle2D r = getBounds();

        double x = r.getX();
        double y = r.getY();
        double a = (r.getWidth() + 1) / 2;
        double b = (r.getHeight() + 1) / 2;

        // x0,y0 - center of ellipse 
        double x0 = x + a;
        double y0 = y + b;

        // x1, y1 - point
        double x1 = p.getX();
        double y1 = p.getY();

        // calculate straight line equation through point and ellipse center
        // y = d * x + h
        double dx = x1 - x0;
        double dy = y1 - y0;

        if ( dx == 0 ) return new Point( (int) x0, (int) (y0 + b * dy / Math.abs( dy )) );

        double d = dy / dx;
        double h = y0 - d * x0;

        // calculate intersection
        double e = a * a * d * d + b * b;
        double f = -2 * x0 * e;
        double g = a * a * d * d * x0 * x0 + b * b * x0 * x0 - a * a * b * b;

        double det = Math.sqrt( f * f - 4 * e * g );

        // two solutions (perimeter points)
        double xout1 = (-f + det) / (2 * e);
        double xout2 = (-f - det) / (2 * e);
        double yout1 = d * xout1 + h;
        double yout2 = d * xout2 + h;

        double dist1Squared = Math.pow( (xout1 - x1), 2 ) + Math.pow( (yout1 - y1), 2 );
        double dist2Squared = Math.pow( (xout2 - x1), 2 ) + Math.pow( (yout2 - y1), 2 );

        // correct solution
        double xout, yout;

        if ( dist1Squared < dist2Squared )
        {
            xout = xout1;
            yout = yout1;
        }
        else
        {
            xout = xout2;
            yout = yout2;
        }

        return getAttributes().createPoint( xout, yout );
    }

    /**
     */
    public CellViewRenderer getRenderer()
    {
        return renderer;
    }

    /**
     */
    public static class EndNodeRenderer extends VertexRenderer
    {
        /**
         * Return a slightly larger preferred size than for a rectangle.
         */
        public Dimension getPreferredSize()
        {
            Dimension d = super.getPreferredSize();
            d.width  += d.width  / 4;
            d.height += d.height / 4;
            
            return d;
        }

        /**
         */
        public void paint( Graphics g )
        {
            int b         = borderWidth;
            Graphics2D g2 = (Graphics2D) g;
            Dimension d   = getSize();
            boolean tmp   = selected;
            
            if ( super.isOpaque() )
            {
                g.setColor( super.getBackground() );
                if ( gradientColor != null && !preview )
                {
                    setOpaque( false );
                    g2.setPaint( new GradientPaint( 0, 0, getBackground(), getWidth(), getHeight(), gradientColor, true ) );
                }
                
                g.fillOval( b - 1, b - 1, d.width - b, d.height - b );
            }
            
            try
            {
                setBorder( null );
                setOpaque( false );
                selected = false;
                super.paint( g );
            }
            finally
            {
                selected = tmp;
            }
            
            if ( bordercolor != null )
            {
                g.setColor( bordercolor );
                g2.setStroke( new BasicStroke( b ) );
                g.drawOval( b - 1, b - 1, d.width - b, d.height - b );
                g.drawOval( b + 3, b + 3, d.width - 9, d.height - 9 );
            }
            if ( selected )
            {
                g2.setStroke( GraphConstants.SELECTION_STROKE );
                g.setColor( highlightColor );
                g.drawOval( b - 1, b - 1, d.width - b, d.height - b );
            }
        }
    }
}